package org.semanticflash.rdf.triple
{
	
	import com.bigflexlib.core.comparison.result.ComparisonResult;
	import com.bigflexlib.core.comparison.result.ComparisonResults;
	import com.bigflexlib.core.comparison.simple.ISimpleComparable;
	import com.bigflexlib.x.Object.ObjectUtil;
	
	import org.semanticflash.rdf.values.IRI;
	import org.semanticflash.rdf.values.RDFValue;
	
	public class RDFTriplePattern implements ISimpleComparable
	{


		
		private var _tripleMask:RDFTriple;

		public function get tripleMask( ):RDFTriple
		{
			return _tripleMask;
		}
		
		
	
	
		/**
		 * 
		 * Contains a triple mask and the names for the variables, if any, used in the tuple.
		 * For example, the following expression
		 * 
		 * foo:bar rdfs:label ?barLabel
		 * 
		 * will result in a pattern composed of
		 * 
		 * a triple( IRI(foo:bar), IRI(rdfs:label), IRI.WILDCARD )
		 * 
		 * and the following varNames object
		 * 
		 * { o:"barLabel" }
		 * 
		 * 
		 * NOTE: varNames must be limited to the actual IRI.WILDCARD values in the pattern.
		 * You MUST NOT pass a varNames object containing {s:"myVar"} if ´s´ is not IRI.WILDCARD.
		 * 
		 * 
		 */	
		public var varNames:Object = {};
	
	
	
	
	
		/**
		 * 
		 * 
		 * 
		 * @param tripleMask a triple that can contain wildcards
		 * @param varNames 
		 * 
		 */	
		public function RDFTriplePattern( tripleMask:RDFTriple, varNames:Object = null )
		{
			_tripleMask = tripleMask;
			
			if ( varNames != null )
			{
				this.varNames = varNames;
			}
		}	
	
	
	
	
	
		/**
		 * 
		 * Performs no checking against statement. Just extracts bindings.
		 * 
		 * @param otherTriple
		 * @return 
		 * 
		 */	
		public function extractBindings( otherTriple:RDFTriple ):Object
		{
			
			var bindings:Object = {};
			
			// we assume a matching statement		
			for ( var termName:String in varNames )
			{
				// termName is one of s, p ,o
				var varName:String = varNames[ termName ];
			
				// varName is the actual varName				
				bindings[ varName ] = otherTriple[ termName ];				
			
			}
			
				
			return bindings;
		}
	
	



		
		
		/**
		 * 
		 * Note. This method will ALWAYS return a new copy. Even if bindings is empty.
		 * It is still an open question wether we should make triple patterns inmutable and valuesingletons
		 * 
		 * @param bindings
		 * @return a new pattern where vars have been replaced with values from bindings if available
		 *          you can ask the triple if it has any wildcards left ( triple.hasWildCards )
		 * 
		 */
		public function getBindedCopy( bindings:Object ):RDFTriplePattern
		{

			// shallow copy
			var newVarNames:Object = ObjectUtil.makeShallowCopy( varNames );
			
			var tuple:Object = { s:tripleMask.s, p:tripleMask.p, o:tripleMask.o };

			for ( var termName:String in varNames )
			{
				var varName:String = varNames[ termName ] as String;
				if ( bindings[ varName ] ) // hooray, we have a value for this binding ;)
				{
					tuple[ termName ] = bindings[ varName ];
					
					delete newVarNames[ termName ];
				}
			}
			
			
			var newTripleMask:RDFTriple = RDFTriple.instance( tuple.s as IRI, tuple.p as IRI, tuple.o as RDFValue );

			return new RDFTriplePattern( newTripleMask , newVarNames );

		}
		
		
		
		
		
		
		
		public function compare( other:* ):ComparisonResult
		{
		
			if ( this === other )
				return ComparisonResults.EQUAL;		
			
			var o:RDFTriplePattern = other as RDFTriplePattern;
			
			if ( o == null )
				return ComparisonResults.DIFFERENT;
		
			if ( ! ObjectUtil.shallowCompare( varNames, o.varNames ) )
				return ComparisonResults.DIFFERENT;
				
			if ( ! tripleMask === o.tripleMask )
				return ComparisonResults.DIFFERENT;
				
			return ComparisonResults.EQUAL;
		
		}
		
		
		
		
		
		

		//////////////////////////////////////////////////////
		///////////////////// factories //////////////////////
		//////////////////////////////////////////////////////



		/**
		 * 
		 * Yoy can pass an RDFValue or a string for each position
		 * and the varNames will be extracted automatically
		 * 
		 * @param s
		 * @param p
		 * @param o
		 * @return 
		 * 
		 */
		public static function instance( s:*, p:*, o:* ):RDFTriplePattern
		{

			var varNames:Object = {};
			if ( s is String )
			{
				varNames.s = s;
				s = IRI.WILDCARD;
			}

			if ( p is String )
			{
				varNames.p = p;
				p = IRI.WILDCARD;
			}

			if ( o is String )
			{
				varNames.o = o;
				o = IRI.WILDCARD;
			}
			
			return new RDFTriplePattern( RDFTriple.instance( s as RDFValue, p as IRI, o as RDFValue ), varNames );
										
		}
		
		
		public static function fromArray( arr:Array ):RDFTriplePattern
		{

			return instance( arr[0], arr[1], arr[2] );

		}
		
		
		
		

		/**
		 * 
		 * 
		 * 
		 * @param str
		 * @return 
		 * 
		 */		
		public static function parseSimple( str:String ):RDFTriplePattern
		{
			
			
			
				
					
			return null;
		}
		
		
		

	}


}